package gu.sql2java.generator;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.BeforeClass;
import org.junit.Test;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;


public class CheckAutoUpdateColumn {
	private static final String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useInformationSchema=true&useSSL=false";
	private static final String user = "root";
	private static final String password = null;
	private static String tableName;
	private static String columnName;
	private static String schema;
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		tableName = System.getProperty("tableName", "xdc_device");
		columnName = System.getProperty("columnName", "update_time");
		schema = System.getProperty("schema", "test");
	}
	/**
	 * 方法一：通过DatabaseMetaData获取EXTRA字段判断是否为自动更新字段<br>
	 * NOTE:验证失败，通过DatabaseMetaData获取 EXTRA字段是徒劳的，它不在 getColumns支持的字段之列
	 * @throws SQLException
	 */
	@Test
    public void test1GetExtraByDatabaseMetaData() throws SQLException {
        
        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            DatabaseMetaData metaData = conn.getMetaData();
            ResultSet columns = metaData.getColumns(null, null, tableName, columnName);
            while (columns.next()) {
                String defaultValue = columns.getString("COLUMN_DEF");
                String extra = columns.getString("EXTRA");
                fail("未找到EXTRA字段");
                boolean isDynamic = "CURRENT_TIMESTAMP".equals(defaultValue) 
                                    && extra != null 
                                    && extra.contains("on update CURRENT_TIMESTAMP");
                System.out.println("[元数据方式] 自动更新字段: " + isDynamic);
            }
        }catch (SQLException e) {
			assertEquals("Column 'EXTRA' not found.", e.getMessage());
		}
    }
	/**
	 * 方法二：查询information_schema，获取EXTRA字段判断是否为自动更新字段
	 * @throws SQLException
	 */
	@Test
	public void test2GetExtraByinformation_schema() throws SQLException {
		
		try (Connection conn = DriverManager.getConnection(url, user, password)) {

			String sql = "SELECT COLUMN_DEFAULT, EXTRA FROM information_schema.columns " 
					+ "WHERE TABLE_SCHEMA= '"
					+ schema + "' AND TABLE_NAME = '" + tableName + "' AND COLUMN_NAME = '" + columnName + "'";
			try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) {
				if (rs.next()) {
					String defaultValue = rs.getString("COLUMN_DEFAULT");
					String extra = rs.getString("EXTRA");
					boolean isDynamic = "CURRENT_TIMESTAMP".equals(defaultValue)
							&& extra.contains("on update CURRENT_TIMESTAMP");
					System.out.println("[直接查询方式] 自动更新字段: " + isDynamic);
				}
			}
		}
	}
	@Test
	public void test3GetExtraByinformation_schema() throws SQLException {

		try (Connection conn = DriverManager.getConnection(url, user, password)) {
			boolean isAutoUpdateColumn = isAutoUpdateColumn(conn, schema, tableName, columnName);
			System.out.println("[直接查询方式] 自动更新字段: " + isAutoUpdateColumn);
			assertTrue(isAutoUpdateColumn);
		}
	}

	/**
	 * 检查指定数据库连接、模式、表和列是否为自动更新列。<p>
	 * 该方法通过查询 information_schema.columns 表，获取指定列的 EXTRA 字段信息，<br>
	 * 并判断该字段是否包含 "ON UPDATE" 来确定该列是否为自动更新列。<p>
	 * 
	 * @param conn 数据库连接对象，不能为 null。
	 * @param schema 数据库模式名，不能为 null 或空字符串。
	 * @param tableName 表名，不能为 null 或空字符串。
	 * @param columnName 列名，不能为 null 或空字符串。
	 * @return 如果该列是自动更新列，则返回 true；否则返回 false。
	 * @throws SQLException 如果在执行查询过程中发生 SQL 异常，或者未找到指定列，将抛出该异常。
	 */
	public static boolean isAutoUpdateColumn(Connection conn, String schema, String tableName, String columnName)
			throws SQLException {
		checkArgument(conn != null, "conn is null");
		checkArgument(!isNullOrEmpty(schema), "schema is null or empty");
		checkArgument(!isNullOrEmpty(tableName), "tableName is null or empty");
		checkArgument(!isNullOrEmpty(columnName), "columnName is null or empty");
		try (PreparedStatement preparedStatement = prepareColumnMetadataQuery(conn, schema, tableName, columnName);
				ResultSet rs = preparedStatement.executeQuery()) {
			if (rs.next()) {
				String extra = rs.getString("EXTRA");
				return null == extra ? false : extra.toUpperCase().contains("ON UPDATE");
			}else {
				throw new SQLException("NOT FOUND COLUMN : " + columnName + " in TABLE : " + tableName + " in SCHEMA : "
						+ schema + " in DATABASE : " + conn.getCatalog() + "");
			}
		}
	}

	/**
	 * 准备一个用于查询指定数据库模式、表和列的元数据的预编译语句。<p>
	 * 该方法构建一个 SQL 查询语句，用于从 information_schema.columns 表中获取指定列的元数据信息。<br>
	 * 然后使用传入的数据库连接对象创建并配置预编译语句，将模式名、表名和列名作为参数绑定到预编译语句中。<p>
	 * 
	 * @param conn 数据库连接对象，用于创建预编译语句，不能为 null。
	 * @param schema 数据库模式名，用于指定查询的数据库模式，不能为 null 或空字符串。
	 * @param tableName 表名，用于指定查询的表，不能为 null 或空字符串。
	 * @return 一个配置好的预编译语句对象，可用于执行查询操作。
	 * @throws SQLException 如果在创建预编译语句过程中发生 SQL 异常，将抛出该异常。
	 */
	private static PreparedStatement prepareColumnMetadataQuery(Connection conn, String schema, String tableName,
			String columnName) throws SQLException {
		String sql = "SELECT * FROM information_schema.columns "
				+ "WHERE TABLE_SCHEMA= ? AND TABLE_NAME = ? AND COLUMN_NAME = ?";
		PreparedStatement preparedStatement = conn.prepareStatement(sql);
		preparedStatement.setString(1, schema);
		preparedStatement.setString(2, tableName);
		preparedStatement.setString(3, columnName);
		return preparedStatement;
	}
}
